use salvo::prelude::*;
use serde::Serialize;
use thiserror::Error;
use std::error::Error as StdError;

// 错误位置信息结构体
#[derive(Debug, Clone, Serialize)]
pub struct ErrorLocation {
    pub file: String,
    pub line: u32,
    pub column: u32,
}

impl ErrorLocation {
    #[track_caller]
    pub fn capture() -> Self {
        let location = std::panic::Location::caller();
        Self {
            file: location.file().to_string(),
            line: location.line(),
            column: location.column(),
        }
    }

    pub fn format(&self) -> String {
        format!("{}:{}:{}", self.file, self.line, self.column)
    }
}

// 定义应用级别的错误类型，支持错误链和source追踪
#[derive(Error, Debug)]
pub enum AppError {
    #[error("数据库错误: {message}")]
    Database { 
        message: String,
        location: ErrorLocation,
        #[source] 
        source: Option<Box<dyn std::error::Error + Send + Sync>>,
    },
    
    #[error("验证失败: {message}")]
    Validation { 
        message: String,
        location: ErrorLocation,
        #[source] 
        source: Option<Box<dyn std::error::Error + Send + Sync>>,
    },
    
    #[error("权限不足")]
    Unauthorized { 
        location: ErrorLocation,
        #[source] 
        source: Option<Box<dyn std::error::Error + Send + Sync>>,
    },
    
    #[error("资源未找到: {message}")]
    NotFound { 
        message: String,
        location: ErrorLocation,
        #[source] 
        source: Option<Box<dyn std::error::Error + Send + Sync>>,
    },
    
    #[error("内部服务器错误: {message}")]
    Internal { 
        message: String,
        location: ErrorLocation,
        #[source] 
        source: Option<Box<dyn std::error::Error + Send + Sync>>,
    },
    
    #[error("外部服务错误: {message}")]
    ExternalService { 
        message: String,
        location: ErrorLocation,
        #[source] 
        source: Option<Box<dyn std::error::Error + Send + Sync>>,
    },
}

// 错误响应的结构体，用于JSON序列化
#[derive(Serialize, Debug)]
pub struct ErrorResponse {
    pub error: bool,
    pub message: String,
    pub code: u16,
    #[serde(rename = "type")]
    pub error_type: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub details: Option<ErrorDetails>,
}

#[derive(Serialize, Debug)]
pub struct ErrorDetails {
    pub location: String,
    pub timestamp: String,
    pub request_id: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub source_chain: Option<Vec<String>>,
}

impl AppError {
    // 错误创建方法，自动捕捉调用位置
    #[track_caller]
    pub fn validation(message: &str) -> Self {
        let location = ErrorLocation::capture();
        
        // 自动记录错误日志
        tracing::error!(
            error_type = "ValidationError",
            message = message,
            location = %location.format(),
            "Error created"
        );
        
        Self::Validation { 
            message: message.to_string(),
            location,
            source: None,
        }
    }
    
    #[track_caller]
    pub fn validation_with_source<E>(message: &str, source: E) -> Self 
    where
        E: std::error::Error + Send + Sync + 'static,
    {
        let location = ErrorLocation::capture();
        
        tracing::error!(
            error_type = "ValidationError",
            message = message,
            source = %source,
            location = %location.format(),
            "Error created with source"
        );
        
        Self::Validation { 
            message: message.to_string(),
            location,
            source: Some(Box::new(source)),
        }
    }
    
    #[track_caller]
    pub fn not_found(resource: &str) -> Self {
        let location = ErrorLocation::capture();
        
        tracing::error!(
            error_type = "NotFoundError",
            resource = resource,
            location = %location.format(),
            "Resource not found"
        );
        
        Self::NotFound { 
            message: resource.to_string(),
            location,
            source: None,
        }
    }
    
    #[track_caller]
    pub fn not_found_with_source<E>(resource: &str, source: E) -> Self 
    where
        E: std::error::Error + Send + Sync + 'static,
    {
        let location = ErrorLocation::capture();
        
        tracing::error!(
            error_type = "NotFoundError",
            resource = resource,
            source = %source,
            location = %location.format(),
            "Resource not found with source"
        );
        
        Self::NotFound { 
            message: resource.to_string(),
            location,
            source: Some(Box::new(source)),
        }
    }
    
    #[track_caller]
    pub fn internal(message: &str) -> Self {
        let location = ErrorLocation::capture();
        
        tracing::error!(
            error_type = "InternalError",
            message = message,
            location = %location.format(),
            "Internal error"
        );
        
        Self::Internal { 
            message: message.to_string(),
            location,
            source: None,
        }
    }
    
    #[track_caller]
    pub fn internal_with_source<E>(message: &str, source: E) -> Self 
    where
        E: std::error::Error + Send + Sync + 'static,
    {
        let location = ErrorLocation::capture();
        
        tracing::error!(
            error_type = "InternalError",
            message = message,
            source = %source,
            location = %location.format(),
            "Internal error with source"
        );
        
        Self::Internal { 
            message: message.to_string(),
            location,
            source: Some(Box::new(source)),
        }
    }
    
    #[track_caller]
    pub fn database(message: &str) -> Self {
        let location = ErrorLocation::capture();
        
        tracing::error!(
            error_type = "DatabaseError",
            message = message,
            location = %location.format(),
            "Database error"
        );
        
        Self::Database { 
            message: message.to_string(),
            location,
            source: None,
        }
    }
    
    #[track_caller]
    pub fn database_with_source<E>(message: &str, source: E) -> Self 
    where
        E: std::error::Error + Send + Sync + 'static,
    {
        let location = ErrorLocation::capture();
        
        tracing::error!(
            error_type = "DatabaseError",
            message = message,
            source = %source,
            location = %location.format(),
            "Database error with source"
        );
        
        Self::Database { 
            message: message.to_string(),
            location,
            source: Some(Box::new(source)),
        }
    }
    
    #[track_caller]
    pub fn unauthorized() -> Self {
        let location = ErrorLocation::capture();
        
        tracing::warn!(
            error_type = "UnauthorizedError",
            location = %location.format(),
            "Unauthorized access attempt"
        );
        
        Self::Unauthorized { 
            location,
            source: None,
        }
    }

    // 从任意错误转换的通用方法
    #[track_caller]
    pub fn from_error<E>(error_type: &str, message: &str, source: E) -> Self 
    where
        E: std::error::Error + Send + Sync + 'static,
    {
        let location = ErrorLocation::capture();
        
        tracing::error!(
            error_type = error_type,
            message = message,
            source = %source,
            location = %location.format(),
            "Error converted from source"
        );
        
        match error_type {
            "validation" => Self::Validation { 
                message: message.to_string(), 
                location, 
                source: Some(Box::new(source)) 
            },
            "database" => Self::Database { 
                message: message.to_string(), 
                location, 
                source: Some(Box::new(source)) 
            },
            "internal" => Self::Internal { 
                message: message.to_string(), 
                location, 
                source: Some(Box::new(source)) 
            },
            "not_found" => Self::NotFound { 
                message: message.to_string(), 
                location, 
                source: Some(Box::new(source)) 
            },
            _ => Self::Internal { 
                message: format!("{}: {}", error_type, message), 
                location, 
                source: Some(Box::new(source)) 
            },
        }
    }
    
    // 获取错误位置
    pub fn location(&self) -> &ErrorLocation {
        match self {
            AppError::Database { location, .. } => location,
            AppError::Validation { location, .. } => location,
            AppError::Unauthorized { location, .. } => location,
            AppError::NotFound { location, .. } => location,
            AppError::Internal { location, .. } => location,
            AppError::ExternalService { location, .. } => location,
        }
    }
    
    // 根据错误类型获取HTTP状态码
    pub fn status_code(&self) -> StatusCode {
        match self {
            AppError::Database { .. } => StatusCode::INTERNAL_SERVER_ERROR,
            AppError::Validation { .. } => StatusCode::BAD_REQUEST,
            AppError::Unauthorized { .. } => StatusCode::UNAUTHORIZED,
            AppError::NotFound { .. } => StatusCode::NOT_FOUND,
            AppError::Internal { .. } => StatusCode::INTERNAL_SERVER_ERROR,
            AppError::ExternalService { .. } => StatusCode::BAD_GATEWAY,
        }
    }
    
    // 获取错误类型字符串
    pub fn error_type(&self) -> &'static str {
        match self {
            AppError::Database { .. } => "DatabaseError",
            AppError::Validation { .. } => "ValidationError",
            AppError::Unauthorized { .. } => "UnauthorizedError",
            AppError::NotFound { .. } => "NotFoundError",
            AppError::Internal { .. } => "InternalError",
            AppError::ExternalService { .. } => "ExternalServiceError",
        }
    }
    
    // 检查是否应该显示详细信息
    fn should_show_details(&self, _req: &Request, _depot: &Depot) -> bool {
        std::env::var("APP_ENV").unwrap_or_else(|_| "production".to_string()) == "development"
    }
    
    // 构建错误源链
    fn build_source_chain(&self) -> Vec<String> {
        let mut chain = Vec::new();
        let mut current_source = self.source();
        
        while let Some(source) = current_source {
            chain.push(source.to_string());
            current_source = source.source();
        }
        
        chain
    }
    
    // 构建错误响应
    fn to_error_response(&self, req: &Request, depot: &Depot) -> ErrorResponse {
        let show_details = self.should_show_details(req, depot);
        
        ErrorResponse {
            error: true,
            message: if show_details {
                self.to_string()
            } else {
                // 生产环境下的用户友好消息
                match self {
                    AppError::Database { .. } => "服务暂时不可用，请稍后重试".to_string(),
                    AppError::Internal { .. } => "内部错误，请联系管理员".to_string(),
                    AppError::ExternalService { .. } => "外部服务异常，请稍后重试".to_string(),
                    _ => self.to_string(), // 对于用户错误，显示原始消息
                }
            },
            code: self.status_code().as_u16(),
            error_type: self.error_type().to_string(),
            details: if show_details {
                let source_chain = self.build_source_chain();
                Some(ErrorDetails {
                    location: self.location().format(),
                    timestamp: chrono::Utc::now().to_rfc3339(),
                    request_id: req.headers().get("x-request-id")
                        .and_then(|v| v.to_str().ok())
                        .map(|s| s.to_string()),
                    source_chain: if source_chain.is_empty() { None } else { Some(source_chain) },
                })
            } else {
                None
            },
        }
    }
}

// 为AppError实现Writer trait
#[async_trait::async_trait]
impl Writer for AppError {
    async fn write(mut self, req: &mut Request, depot: &mut Depot, res: &mut Response) {
        let error_response = self.to_error_response(req, depot);
        
        res.status_code(self.status_code());
        res.render(Json(error_response));
    }
}

// 定义应用级别的Result类型
pub type AppResult<T> = Result<T, AppError>;

// 便捷的错误创建宏，支持自动位置捕捉
macro_rules! app_error {
    (validation, $msg:expr) => {
        AppError::validation($msg)
    };
    (validation, $msg:expr, $source:expr) => {
        AppError::validation_with_source($msg, $source)
    };
    (not_found, $resource:expr) => {
        AppError::not_found($resource)
    };
    (not_found, $resource:expr, $source:expr) => {
        AppError::not_found_with_source($resource, $source)
    };
    (internal, $msg:expr) => {
        AppError::internal($msg)
    };
    (internal, $msg:expr, $source:expr) => {
        AppError::internal_with_source($msg, $source)
    };
    (database, $msg:expr) => {
        AppError::database($msg)
    };
    (database, $msg:expr, $source:expr) => {
        AppError::database_with_source($msg, $source)
    };
    (unauthorized) => {
        AppError::unauthorized()
    };
    (from, $error_type:expr, $msg:expr, $source:expr) => {
        AppError::from_error($error_type, $msg, $source)
    };
}

// 用于演示错误链的辅助函数
fn simulate_io_error() -> std::io::Result<()> {
    Err(std::io::Error::new(
        std::io::ErrorKind::ConnectionRefused,
        "Connection refused by database server"
    ))
}

fn simulate_parse_error() -> Result<i32, std::num::ParseIntError> {
    "invalid_number".parse::<i32>()
}

// Handler for English greeting - 演示验证错误
#[handler]
async fn hello() -> AppResult<&'static str> {
    Err(app_error!(validation, "用户输入验证失败"))
}

// Handler demonstrating not found error
#[handler]
async fn not_found_demo() -> AppResult<&'static str> {
    Err(app_error!(not_found, "用户ID: 12345"))
}

// Handler demonstrating internal error
#[handler]
async fn internal_error_demo() -> AppResult<&'static str> {
    Err(app_error!(internal, "配置文件解析失败"))
}

// Handler demonstrating database error
#[handler]
async fn database_error_demo() -> AppResult<&'static str> {
    Err(app_error!(database, "连接池已满"))
}

// Handler demonstrating error chaining with source
#[handler]
async fn error_chain_demo() -> AppResult<&'static str> {
    // 模拟IO错误并包装成数据库错误
    if let Err(io_err) = simulate_io_error() {
        return Err(app_error!(database, "数据库连接失败", io_err));
    }
    Ok("不会到达这里")
}

// Handler demonstrating parse error chaining
#[handler]
async fn parse_error_demo() -> AppResult<&'static str> {
    // 模拟解析错误并包装成验证错误
    if let Err(parse_err) = simulate_parse_error() {
        return Err(app_error!(validation, "无效的数字格式", parse_err));
    }
    Ok("不会到达这里")
}

// Handler demonstrating generic error conversion
#[handler]
async fn generic_error_demo() -> AppResult<&'static str> {
    let custom_err = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "Access denied");
    Err(app_error!(from, "permission", "权限验证失败", custom_err))
}

// Handler for successful response
#[handler]
async fn success() -> AppResult<&'static str> {
    Ok("Hello, Salvo! 一切正常!")
}

// Handler for Chinese greeting
#[handler]
async fn hello_zh() -> AppResult<&'static str> {
    Ok("你好，世界！")
}

#[tokio::main]
async fn main() {
    // Initialize logging subsystem
    tracing_subscriber::fmt()
        .with_env_filter("salvo_demo=debug,salvo=info")
        .init();

    // Bind server to port 5800
    let acceptor = TcpListener::new("0.0.0.0:5800").bind().await;

    // Create router with multiple error demonstration endpoints
    let router = Router::new()
        .get(hello)
        .push(Router::with_path("success").get(success))
        .push(Router::with_path("not-found").get(not_found_demo))
        .push(Router::with_path("internal").get(internal_error_demo))
        .push(Router::with_path("database").get(database_error_demo))
        .push(Router::with_path("error-chain").get(error_chain_demo))
        .push(Router::with_path("parse-error").get(parse_error_demo))
        .push(Router::with_path("generic-error").get(generic_error_demo))
        .push(Router::with_path("你好").get(hello_zh));

    // Print available endpoints
    println!("🚀 Server starting on http://localhost:5800");
    println!("📍 Available endpoints:");
    println!("  GET /             - 验证错误演示");
    println!("  GET /success      - 成功响应演示");
    println!("  GET /not-found    - 资源未找到错误演示");
    println!("  GET /internal     - 内部错误演示");
    println!("  GET /database     - 数据库错误演示");
    println!("  GET /error-chain  - 错误链演示 (IO错误->数据库错误)");
    println!("  GET /parse-error  - 解析错误链演示");
    println!("  GET /generic-error - 通用错误转换演示");
    println!("  GET /你好          - 中文问候");
    println!("💡 提示: 设置环境变量 APP_ENV=development 查看详细错误信息");

    // Start serving requests
    Server::new(acceptor).serve(router).await;
}